﻿using System;
using System.Windows;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Collections.Generic;

using SBPweb.Forge.Common.Patterns;

#if SILVERLIGHT
using SBPweb.Forge.Controls.Silverlight;
using SBPweb.Forge.Controls.Silverlight.Utilities;
#endif

namespace SBPweb.GoogleDataAPI.Client.Connector.Services
{

    public class ServiceConnector
    {

        #region Private fields

        private static Dictionary<Type, object> clientCache = new Dictionary<Type, object>();
        private static LockHelper lh = new LockHelper();

        #endregion

        #region Constructor logic

        static ServiceConnector()
        {
#if SILVERLIGHT
            DnsSafeHost = Application.Current.Host.Source.DnsSafeHost;
#else
            //DnsSafeHost = Application.Current.
#endif
        }

        public ServiceConnector()
        {
        }

        #endregion

        #region Property accessors

#if SILVERLIGHT
        internal static InitialParameters ApplicationInitialParameters
        {
            get
            {
                return (Application.Current as ExtendableApplication).Get<InitialParameters>("InitialParameters");
            }
        }
#else
        private static SingletonHelper<InitialParameters> initParams = new SingletonHelper<InitialParameters>();

        internal static InitialParameters ApplicationInitialParameters
        {
            get
            {
                return initParams.Instance;
            }
        }
#endif

        #endregion

        #region Properties

        public static string DnsSafeHost
        {
            get;
            set;
        }

        public static Uri OverriddenServiceHostRoot
        {
            get;
            protected set;
        }

        #endregion

        #region Events

        public static event EventHandler<UriOverrideEventArgs> UriOverriding;

        #endregion

        #region Methods

        public static TClient CreateServiceClientInstance<TClient, TChannel>()
            where TClient : ClientBase<TChannel>
            where TChannel : class
        {
            Type type = typeof(TClient);
            using (lh.GetLock())
            {
                if (!clientCache.ContainsKey(type))
                {
                    TClient client = Activator.CreateInstance<TClient>();
                    Uri uri = client.Endpoint.Address.Uri;
                    uri = OnUriOverride(uri);
                    OverriddenServiceHostRoot = new Uri(string.Format("{0}://{1}:{2}{3}", uri.Scheme, uri.DnsSafeHost, uri.Port, uri.LocalPath.Substring(0, uri.LocalPath.LastIndexOf('/'))));
                    client.Endpoint.Address = new EndpointAddress(uri.ToString());
                    clientCache.Add(type, client);
                    return client;
                }
                else
                {
                    return (TClient)clientCache[type];
                }
            }
        }

        public static TClient CreateServiceClientInstance<TClient, TChannel>(Type type)
            where TClient : class
            where TChannel : class
        {
            using (lh.GetLock())
            {
                if (!clientCache.ContainsKey(type))
                {
                    TClient client = null;
                    try
                    {
                        client = Activator.CreateInstance<TClient>();
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                    PropertyInfo pI = type.GetProperty("Endpoint");
                    ServiceEndpoint sEp = (pI.GetValue(client, null) as ServiceEndpoint);
                    Uri uri = sEp.Address.Uri;
                    uri = OnUriOverride(uri);
                    OverriddenServiceHostRoot = new Uri(string.Format("{0}://{1}:{2}{3}", uri.Scheme, uri.DnsSafeHost, uri.Port, uri.LocalPath.Substring(0, uri.LocalPath.LastIndexOf('/'))));
                    sEp.Address = new EndpointAddress(uri.ToString());
                    clientCache.Add(type, client);
                    return client;
                }
                else
                {
                    return (TClient)clientCache[type];
                }
            }
        }

        public static OperationContextScope CreateServiceClientScope<TChannel>(ClientBase<TChannel> client)
            where TChannel : class
        {
            OperationContextScope scope = new OperationContextScope(client.InnerChannel);
            if (ApplicationInitialParameters != null)
            {
                OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("UserToken", "SBPwebTech", ApplicationInitialParameters.Get<string>("UserToken")));
                OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("UserHost", "SBPwebTech", ApplicationInitialParameters.Get<string>("ClientIp")));
            }
            return scope;
        }

        protected static Uri OnUriOverride(Uri uri)
        {
            UriOverrideEventArgs uoea = new UriOverrideEventArgs(uri);
            if (UriOverriding != null)
            {
                UriOverriding(null, uoea);
            }
            return uoea.Uri;
        }

        #endregion

        #region Subclasses

        public class UriOverrideEventArgs : EventArgs
        {

            public UriOverrideEventArgs(Uri uri)
            {
                this.Uri = uri;
            }

            public Uri Uri
            {
                get;
                set;
            }

        }

        #endregion

    }

}